home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / intrvews / xgrab.lha / xgrab / ui / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-07  |  10.5 KB  |  433 lines

  1. /**
  2.    GRAB Graph Layout and Browser System
  3.  
  4.    Copyright (c) 1986, 1988 Regents of the University of California
  5.    Copyright (c) 1989, Tera Computer Company
  6.  **/
  7.  
  8.   /* output.c contains procedures to draw a layed out digraph.  */
  9.  
  10. #include "malloc.h"
  11. #include <math.h>
  12.  
  13. #include "attribute.h"
  14. #include "digraph.h"
  15. #include "screen.h"
  16. #include "scrdep.h"
  17. #include "globals.h"
  18. #include "interf.h"
  19. #include "tedge.h"
  20. #include "cursor.h"
  21. #include "clip.h"
  22.  
  23. BOOL on_screen(), edge_on_screen();
  24. NODE *get_prev_node(), *get_next_node();
  25. char *get_edge_label();
  26. OUTEDGE *get_edge();
  27. void NewFont();
  28.  
  29. void DoGraph()
  30.   /** 
  31.      draw the graph.  First set up the font.  Then make sure the screen
  32.      variable is et correctly.  Then add the nodes to the graph.
  33.      Then draw it.
  34.    **/
  35. {
  36.     NODE *node;
  37.  
  38.     if (digraph == NULL) 
  39.     {
  40.     IChangeStatusLine("No digraph to display", FALSE);
  41.     return;
  42.     }
  43.  
  44.     ISetCursor(waitC);
  45.  
  46.     if (digraph->lastnode != -1)
  47.       /* there is something to display */
  48.     {
  49.         IChangeStatusLine("Drawing Graph", TRUE);
  50.     }
  51.  
  52.     IEraseGraph();
  53.     NewFont();
  54.  
  55.     ReCalcScreen();
  56.  
  57.       /* foreach node on the current node list, print out node and edges */
  58.     each_node(digraph, node)
  59.     loop
  60.     draw_node(digraph, node, &screen, FALSE);
  61.     draw_out_edges(digraph, node, &screen, FALSE);
  62.     endloop
  63.     
  64.     IUpdateG();
  65.     IUnsetCursor();
  66. } /* DoGraph */
  67.  
  68. void NewFont()
  69. {
  70.     int sizex, sizey;
  71.     int a, b, c, d, e, f;
  72.     int width, height;
  73.  
  74.       /* find size of font to use */
  75.     IGetBounds (&a, &b, &width, &height, &c, &d, &e, &f);
  76.  
  77.     sizex = width /
  78.             ((float)(screen.absview.max_x - screen.absview.min_x) / 
  79.          (float)(HALF_CHAR * 2));
  80.     sizey = get_height(digraph) * ((float) height /
  81.            (float)(screen.absview.max_y - screen.absview.min_y));
  82.     ISetFont(sizex, sizey);
  83. }
  84.  
  85. double GetHeight()
  86.   /* returns the height of a node in relation to the height of the digraph */
  87. {
  88.     return (double) get_height(digraph) / 
  89.        (double) (screen.absview.max_y - screen.absview.min_y);
  90. }
  91.  
  92. get_height(digraph)
  93. DIGRAPH *digraph;
  94.   /* returns the height of one node */
  95. {
  96.     NODE *node;
  97.  
  98.     each_node(digraph, node)
  99.     loop
  100.         if (Half_height(node) != 0)
  101.     {
  102.             return (Half_height(node) + Half_height(node));
  103.     }
  104.     endloop
  105.  
  106.       /* if no nodes, return what height a node would have */
  107.     return ((NODE_HALF_HEIGHT + 2) * 2);
  108. }
  109.  
  110. draw_node(digraph, node, screen, draw)
  111. DIGRAPH *digraph;
  112. NODE *node;         /* node to draw */
  113. SCREEN *screen;        /* window information */
  114. BOOL draw;          /* draw it now, or wait? */
  115.   /**
  116.      draw_node draws a node, including its name, outgoing edges, and
  117.      barycenters (optional).
  118.    **/
  119. {
  120.     char *text;
  121.     char upbc[20];             /* up bc */
  122.     char downbc[20];         /* down bc */
  123.  
  124.     if (on_screen(node))        /* shortcut.  Saves mucho time */
  125.     {
  126.         if (!(Is_dummy(node)))
  127.         {
  128.             text = Text(node);
  129.         }
  130.         else
  131.         {
  132.             strsave(text, NULL_STRING);
  133.         }
  134.     
  135.         if (Has_bc(node, UP)) 
  136.         {
  137.             sprintf(upbc, "%d/%3.1f", Priority(node, UP), Bc(node, UP));
  138.         }
  139.         else
  140.         {
  141.             strcpy(upbc, NULL_STRING);
  142.         }
  143.     
  144.         if (Has_bc(node, DOWN)) 
  145.         {
  146.             sprintf(downbc, "%d/%3.1f", Priority(node, DOWN), Bc(node, DOWN));
  147.         }
  148.         else
  149.         {
  150.             strcpy(downbc, NULL_STRING);
  151.         }
  152.     
  153.     if (Is_dummy(node))
  154.       /**
  155.          dummies actually represent many small subnodes in the case
  156.          of multigraphs, one for each edge that goes through it
  157.        **/
  158.     {
  159.         int i;
  160.  
  161.         for (i = max_edges(node, node); i > 0; i--)
  162.         {
  163.         if (get_edge(digraph, node, node, i) != NULL)
  164.           /* edge for this subnode could have been deleted */
  165.         {
  166.             int shift;
  167.  
  168.             shift = ORD_TO_SHIFT(i);
  169.  
  170.             if (markDummyNodes)
  171.             {
  172.                 IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) + 
  173.                                    shift), 
  174.                               (int) ABSY_TO_SCRY(screen, Y_position(node)), 
  175.                           1, 1, 
  176.                             RECTANGLE, text, Is_dummy(node), 
  177.                   (char *) node, upbc, downbc, 
  178.                   Brush(node), Color(node), draw, i);
  179.             }
  180.             else
  181.             {
  182.                     IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) +
  183.                                    shift), 
  184.                               (int) ABSY_TO_SCRY(screen, Y_position(node)), 
  185.                           0, 0, 
  186.                             POINT, text, Is_dummy(node), 
  187.                   (char *) node, upbc, downbc, 
  188.                   Brush(node), Color(node), draw, i);
  189.             }
  190.         }
  191.         }
  192.     }
  193.     else
  194.     {
  195.         IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node)),
  196.                   (int) ABSY_TO_SCRY(screen, Y_position(node)),
  197.               (int) SCALE_X(screen, Half_width(node)),
  198.               (int) SCALE_Y(screen, Half_height(node)),
  199.                 Shape(node), text, Is_dummy(node), (char *) node,
  200.               upbc, downbc, Brush(node), Color(node), draw, -1);
  201.         }
  202.     }
  203. } /* draw_node */
  204.  
  205. draw_edge(digraph, e, fromnode, tonode, ord, screen, draw)
  206. DIGRAPH *digraph;
  207. OUTEDGE *e;
  208. NODE *fromnode, *tonode;
  209. int ord;
  210. SCREEN *screen;
  211. BOOL draw;
  212.   /**
  213.      draw the edge from fromnode to tonode of ord ord.
  214.      most of the time a get_edge was done just before this was called,
  215.      so I decided to make the caller pass the result of that call (e).  And
  216.      if it wasn't done, he can do it.  Saves time
  217.    **/
  218. {
  219.     double from_x;        /* x-coordinate of start of edge */
  220.     double from_y;            /* y-coordinates of start of edge */
  221.     double to_x;        /* x-coordinate of end of edge */
  222.     double to_y;        /* y-coordinates of end of edge */
  223.     NODE *prevnode;
  224.     TEDGE *edge;
  225.     BOOL parrow, reversed;
  226.     BRUSH brush;
  227.     COLOR color;
  228.  
  229.     if (edge_on_screen(fromnode, tonode))    /* time-saver */
  230.     {
  231.         parrow = FALSE;
  232.         reversed = FALSE;
  233.  
  234.           /**
  235.          We don't switch tonode and fromnode if the edge is
  236.          reversed, which makes it very compatible with most
  237.          of the rest of the code
  238.        **/
  239.         edge = (TEDGE *) malloc(sizeof(TEDGE));
  240.         edge->label = Is_dummy(fromnode) ? NULL_STRING : Label(e);
  241.         edge->tonode = (char *) tonode;
  242.         edge->fromnode = (char *) fromnode;
  243.     edge->ord = ord;
  244.  
  245.           /* clip in both directions */
  246.         Clip(fromnode, tonode, ord, &from_x, &from_y, &to_x, &to_y, screen);
  247.     
  248.         if (!Is_dummy(fromnode) && Edge_reversed(e))
  249.         {
  250.             parrow = TRUE;
  251.             reversed = TRUE;
  252.         } 
  253.         else if (!Is_dummy(tonode) && !Edge_reversed(e)) 
  254.         {
  255.             parrow = TRUE;
  256.         }
  257.     
  258.     brush = Brush(e);
  259.     color = Color(e);
  260.     
  261.         if (reversed)
  262.         {
  263.             IAddEdge(
  264.                      (int) ABSX_TO_SCRX(screen, to_x), 
  265.                      (int) ABSY_TO_SCRY(screen, to_y), 
  266.                         (int) ABSX_TO_SCRX(screen, from_x), 
  267.                      (int) ABSY_TO_SCRY(screen, from_y), 
  268.                      parrow, (char *) edge, edge->label, Brush(e), Color(e), 
  269.              draw, ord);
  270.         }
  271.         else
  272.         {
  273.             IAddEdge(
  274.                         (int) ABSX_TO_SCRX(screen, from_x), 
  275.                      (int) ABSY_TO_SCRY(screen, from_y), 
  276.                      (int) ABSX_TO_SCRX(screen, to_x), 
  277.                      (int) ABSY_TO_SCRY(screen, to_y), 
  278.                      parrow, (char *) edge, edge->label, Brush(e), Color(e), 
  279.              draw, ord);
  280.     }
  281.     }
  282. }
  283.  
  284. draw_out_edges(digraph, node, screen, draw)
  285. DIGRAPH *digraph;
  286. NODE *node;    /* node with edges */
  287. SCREEN *screen;
  288. BOOL draw;
  289.   /**
  290.      draw_out_edges draws the out-going edges of node.
  291.    **/
  292. {
  293.     VNO to_vno;            /* each succedent node */
  294.     NODE *tonode;
  295.     OUTEDGE *e;
  296.     int i;
  297.  
  298.     each_element(Succ_set(node), to_vno)
  299.     loop
  300.     tonode = Node(digraph, to_vno);
  301.  
  302.     for (i = max_edges(node, tonode); i > 0; i--)
  303.     {
  304.         if ((e = get_edge(digraph, node, tonode, i)) != NULL)
  305.         {
  306.             draw_edge(digraph, e, node, tonode, i, screen, draw);
  307.         }
  308.     }
  309.     endloop
  310. } /* draw_out_edges */
  311.  
  312.   /**
  313.      We should find all references to these next two routines
  314.      and delete them.  This information is derivable with a call to
  315.      get_edge
  316.    **/
  317. outedge_reversed(digraph, node, tonode, ord)
  318. DIGRAPH *digraph;
  319. NODE *node, *tonode;
  320. int ord;
  321. {
  322.     OUTEDGE *outedge;
  323.     NODE *get_next_node();
  324.  
  325.     /* node at end of reverse edge is a dummy - can't be ... */
  326.     if (Is_dummy(node)) 
  327.     {
  328.     return FALSE;
  329.     }
  330.  
  331.     if (Is_dummy(tonode)) 
  332.     {
  333.     tonode = get_next_node(digraph, tonode);
  334.     }
  335.  
  336.     if ((outedge = get_edge(digraph, node, tonode, ord)) != NULL)
  337.     {
  338.         return Edge_reversed(outedge);
  339.     }
  340.     else
  341.     {
  342.     return FALSE;
  343.     }
  344. }
  345.  
  346. char *get_edge_label(digraph, node, tonode, ord)
  347. register DIGRAPH *digraph;
  348. register NODE *node, *tonode;
  349. int ord;
  350. {
  351.     register OUTEDGE *outedge;
  352.  
  353.     if (Is_dummy(node))
  354.     {
  355.     return (NULL_STRING);
  356.     }
  357.     else
  358.     {
  359.     if (Is_dummy(tonode))
  360.     {
  361.         tonode = get_next_node(digraph, tonode);
  362.     }
  363.  
  364.       if ((outedge = get_edge(digraph, node, tonode, ord)) != NULL)
  365.     {
  366.         return Label(outedge);
  367.     }
  368.     else
  369.     {
  370.             fprintf(stderr, 
  371.           "get_edge_label: node=%s, tonode=%s, ord=%d, outedge not found\n",
  372.           Text(node), Text(tonode), ord);
  373.             return NULL_STRING;
  374.     }
  375.     }
  376. }
  377.  
  378.   /* the all argument may be useless here; it's only called in one place */
  379. draw_in_edges(digraph, node, screen, draw, all)
  380. DIGRAPH *digraph;
  381. NODE *node;            /* node with edges */
  382. SCREEN *screen;
  383. BOOL draw;
  384. BOOL all;        /* draw the edges no matter what */
  385. {
  386.     VNO from_vno;  /* each antecedent node */
  387.     NODE *fromnode;
  388.     OUTEDGE *e;
  389.     int i;
  390.  
  391.     each_element(Ante_set(node), from_vno)
  392.     loop
  393.     fromnode = Node(digraph, from_vno);
  394.  
  395.     if ((!on_screen(fromnode) && on_screen(node)) || all) 
  396.     {
  397.         for (i = max_edges(fromnode, node); i > 0; i--)
  398.         {
  399.         if ((e = get_edge(digraph, fromnode, node, i)) != NULL)
  400.         {
  401.                 draw_edge(digraph, e, fromnode, node, i, screen, draw);
  402.         }
  403.         }
  404.     }
  405.     endloop
  406. } /* draw_in_edges */
  407.  
  408. BOOL on_screen(node)
  409. NODE *node;
  410. {
  411.     return (X_right(node) >= screen.bound.min_x &&
  412.         X_left(node) <= screen.bound.max_x &&
  413.         Y_top(node) >= screen.bound.min_y &&
  414.         Y_bottom(node) <= screen.bound.max_y);
  415. }
  416.  
  417. BOOL edge_on_screen(fromnode, tonode)
  418. NODE *fromnode, *tonode;
  419. {
  420.     return (! ((Y_position(fromnode) > screen.bound.max_y &&
  421.             Y_position(tonode) > screen.bound.max_y) ||
  422.                (Y_position(fromnode) < screen.bound.min_y &&
  423.             Y_position(tonode) < screen.bound.min_y) ||
  424.                (X_position(fromnode) > screen.bound.max_x &&
  425.             X_position(tonode) > screen.bound.max_x) ||
  426.                (X_position(fromnode) < screen.bound.min_x &&
  427.             X_position(tonode) < screen.bound.min_x)));
  428.      /**
  429.     well, it's _not_ on screen if both endpoints are above, below, 
  430.         to the right of, or to the left of the screen 
  431.       **/
  432. }
  433.